/*
    YmsgIRC - Program enabling YMSG chat clients to use IRC
    Copyright (C) 2011 Crash Daemonicus ( crashenator -at- gmail.com )

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
@file IRC.h
@author crashenator (crashenator -at- gmail.com)
@brief Classes and functions useful for using Internet Relay Chat.

Provides networking, command and interaction code for use as in IRC client code.
*/

#include "network.h"
/**
@brief Internet Relay Chat command class
@details provides methods and information for constructing, manipulating and getting information from IRC commands.

In processing, the original command string is separated into different fields and representations of data. \n
See IrcCommand::process() for more information.

In assembling, several fields of data are used to construct a command string. \n
See IrcCommand::assemble() for more information.
@see irccmdfields
*/
class IrcCommand
{
    public:

        //int mode;
        bool single_incOrigin;
		///< @brief specifies if an Origin field is included in the command after the type field (MISNAMED)
		///< @details this property is currently misnamed as it adds the origin when used in multi-content only.
		///< @deprecated this property is likely to be renamed in the future
        bool singlecontent;///< specifies if the IRC command has a single string-content area
        

        string str;///< a raw/assembled IRC command string
		vector<string> parts;///< substring parts of an IRC command
        /// @addtogroup irccmdfields Command property fields
		/// @{
        string type;///< The type of command (QUIT/JOIN/001)
        string origin;///< The origin field of the command (if any) - nickname or server
        string destination;///< The destination field of the command (if any) - nickname or channel
        string content;///< The contents of the command, possibly including multiple other fields.
        string subcontent;///< The contents of the command, excluding one field from the beginning
        string text;///< The text field of the command (if any)
		/// @}

		/**
		@brief clears property values
		@details conditionally resets/clears property values of the class. (no arbitrary defaults, just "")
		@param [in] mode Specifies what to clear:
		Value       | Behavior
		----------- | --------
		0 (default) | clears str, parts and command fields
		1           | clears str
		2           | clears parts and command fields
		@see str
		@see parts
		@see irccmdfields
		*/
        void init(int mode=0);
        ~IrcCommand();
		/**
		@brief creates an empty IrcCommand object
		@details calls init(), enables SingleContent mode, disables IncludeOrigin mode.
		@see singlecontent
		@see single_incOrigin
		*/
        IrcCommand();
		/**
		@brief creates an IrcCommand object from a command string
		@details assigns IrcCommand::str to the input string and calls IrcCommand::process()
		@param [in] command raw command string
		@see process()
		*/
        IrcCommand(const string& command);
		/**
		@brief creates an IrcCommand object from a command fields
		@details this function assigns the similarly-named properties to the inputs, and then calls IrcCommand::assemble(true)
		@param [in] src origin/sender nickname or server
		@param [in] dst destination nickname or channel
		@param [in] typ type of command (PING/QUIT/001)
		@param [in] cont content section of the command (see process() for elaboration )
		@param [in] singlecont specifies whether the command content is a single text field (see assemble() )
		@param [in] incOrig specifies wherther the origin is to be included after the Type (see assemble() )
		@see assemble()
		*/
        IrcCommand(const string& src,const string& dst,const string& typ,const string& cont,bool singlecont=false, bool incOrig=false);
        
		
		/**
		@brief Shortens the origin string to just the nickname
		@details This function changes origins like nickname!user@hostname to just `nickname`.
		This function only changes the IrcCommand::origin property.
		@return none
		@see origin
		*/
		void shortorigin();

		/**
		@brief Processes a raw command string into data fields
		@details In processing, the original command string is separated into different fields and representations of data. \n
		Commands are broken down in the following way:
		@code

Fictional example command                                           | Properties    |  Example value
------------------------------------------------------------------- | ------------- | ----------------------
Jim512 PING Elizabeth27 something something :something with spaces  |               | 
|----------------------------------------------------------------|  | str           | (too long to display)
|----| |--| |---------| |-------| |-------| |--------------------|  | parts         | (vector of strings)
|----|                                                              | origin        | Jim512 
       |--|                                                         | type          | PING
            |---------|                                             | destination   | Elizabeth27
            |-----------------------------------------------------| | content       | (too long to display)
                        |-----------------------------------------| | subcontent    | (too long to display)
                                             |-------------------|  | text          | something with spaces
		@endcode
		This function only modifies internal properties as shown above.
		@return none
		@see irccmdfields
		@see assemble()
		*/
        void process();


		/**
		@brief Constructs a command string from data fields.
		@details In assembling, several fields of data are used to construct a command string. \n
		See IrcCommand::assemble() for more information.
		In single-content mode: only Type, Destination, Text fields are used to assemble a command.\n
		In multi-content mode: only Type, Content are used. \n
		In multi-content/Include-Origin mode: Type, Origin, Content are used. \n
		This function only modifies the IrcCommand::str property.
		@param client Specifies if a command is constructed coming-from an IRC client. This disables origin-prefixing. (default true)
		@return none
		@see irccmdfields
		@see process
		*/
        void assemble(bool client=true);



        void debug();
};


/**
@brief Internet Relay Chat network class
@details Provides functions and networking (IRC command conditions and NwNetwork message cases) for using an Internet Relay Chat network.
This class is a client-side implementation.
@see irccmdfields
*/
class IRC : public NwNetwork
{
    public:
        bool checkErrors(int nBytes);
        void init();///< resets user and connection settings
        IRC();


		/**
		@brief send an IrcCommand message over the connected socket.
		@details Note: this function requires the IrcCommand message be "assembled" before-hand but does not error-check if it is not.
		@param ic the IrcCommand message to send
		@retval true Success: the command was sent.
		@retval false Failure: there was an error sending the command (check IRC::connection.error).
		@see IrcCommand::assemble()
		*/
        bool sendMsg(const IrcCommand& ic);


		/**
		@brief processes a received command
		@details This function forms the basis for IRC networking, it takes received input and 
		immediately decides what needs to be done; from queuing messages to the program, 
		to automatically replying (authorization), and changing internal information as gathered.

		This function must also queue "Events" as necessary so the program can read of important occurences on this network.
		NwNetwork documentation may clarify this.
		@param ic the IrcCommand message as received
		*/
        void stepIncoming(IrcCommand& ic);


		/**
		@brief reads a queue for Action-messages the program told this object to perform, and carries one of them out.
		@details This function reads the class' Actions queue to see what type of things the program wants it to do, and then performs them either internally or with the IRC network as supported.
		For a less abstract description, you may want to read the NwNetwork documentation.
		@see NwNetwork::stepActions()
		*/
        void stepActions();


		/**
		@brief acquires any one waiting message on the connected socket and processes it.
		@details This function works with IRC::connection (NwConnection) to receive data from the connected socket and form an IrcCommand object; if there are no errors, stepIncoming() is immediately called to process the message.
		@see NwNetwork::stepRecv()
		*/
        void stepRecv();


		/**
		@brief Performs a set of actions based on whether the program is Starting, Continuing, or Quitting at a given moment
		@details This function is called by the program to tell the class what state the program is in and give it a chance perform actions.
		Implementation-wise, this is called when: the program Starts-up, when the program Loops (main program loop), and when the program Quits.\n
		As far as performing a Loop Step, this is just doing a piece of work with each iteration of a loop. \n
		Note: Begin and End states are not called repeatedly, only Continue (NW_STEP) is.\n
		Note: any actions the class performs are expected to only last a moment - this function must Return promptly.
		@param state Which state the program is in at the moment\n
		Behavior depends on the value:
		Value            | Behavior
		---------------- | ----------
		NW_STEP_BEGIN    | None. Class is already ready to be used.
		NW_STEP          | Performs a waiting Action (stepActions()).\nReceives and process a message (stepRecv())
		NW_STEP_END      | Closes the connection socket.
		@see NwNetwork::step()
		*/
        void step(NwStepState state=NW_STEP);

        //void notifyStateText(const string& state);
};
